package com.halixun.d2app.printer;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.input.InputManager;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.InputDevice;

import com.google.gson.Gson;
import com.halixun.d2app.app.MyApplication;
import com.halixun.d2app.bean.print.UsbPrintInfo;
import com.halixun.d2app.utils.PrintReceiptsUtil;
import com.halixun.d2app.utils.ToastUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: MyOrderSystem
 * @Package: com.hlddl.order.printer
 * @ClassName: USBPrinter
 * @Description: java类作用描述
 * @Author: hdx
 * @CreateDate: 2019/10/18 15:15
 * @UpdateUser: hdx
 * @UpdateDate: 2019/10/18 15:15
 * @UpdateRemark: 更新说明：
 * @Version: 1.0
 */
public class USBPrinter {
    public static final String ACTION_USB_PERMISSION = "com.usb.printer.USB_PERMISSION";

    private static USBPrinter mInstance;

    private Context mContext;
    private PendingIntent mPermissionIntent;
    private UsbManager mUsbManager;
    private UsbDeviceConnection mUsbDeviceConnection;

    private UsbEndpoint ep, printerEp;

    private static final int TIME_OUT = 100000;

    private static Map<String, UsbDevice> availableDevice = new HashMap<>();
    private static Map<String, UsbDevice> unAvailableDevice = new HashMap<>();

    private static Map<UsbDevice, UsbDeviceConnection> usbDeviceConnectionList = new HashMap<>();


    private boolean isInit = false;


    private InputManager inputManager;


    public static USBPrinter getInstance() {
        if (mInstance == null) {
            synchronized (USBPrinter.class) {
                if (mInstance == null) {
                    mInstance = new USBPrinter();
                }
            }
        }
        return mInstance;
    }

    /**
     * 初始化打印机，需要与destroy对应
     */
    public static void initPrinter() {
        getInstance().init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void init() {
//        list.clear();
        mContext = MyApplication.getMyContext();
        inputManager = (InputManager) mContext.getSystemService(Context.INPUT_SERVICE);
        mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        mContext.registerReceiver(mUsbDeviceReceiver, filter);
        // 列出所有的USB设备，并且都请求获取USB权限
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        for (UsbDevice device : deviceList.values()) {
            Log.e("USBPrinter1",new Gson().toJson(device));
            handerDevice(device);
        }
        isInit = true;
    }

    private final BroadcastReceiver mUsbDeviceReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            synchronized (this) {
                String action = intent.getAction();
                UsbDevice mUsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (ACTION_USB_PERMISSION.equals(action)) {
                    unAvailableDevice.remove(mUsbDevice.getDeviceName());
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false) && mUsbDevice != null) {
                        handerDevice(mUsbDevice);
                    } else {
                        ToastUtils.showBottomToast("id为：" + mUsbDevice.getDeviceName() + "，" + mUsbDevice.getManufacturerName() + "的" + "USB设备请求被拒绝");
                    }
                } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                    if (mUsbDevice != null) {
                        UsbPrintInfo info = MyApplication.getUsbPrint(mUsbDevice);
                        if (info != null) {
                            MyApplication.removeUsbPrint(info);
                            if (null != listener) {
                                listener.onRemoveUsbPrint(info);
                            }
                        }
                        if (availableDevice.containsKey(mUsbDevice.getDeviceName())) {
                            availableDevice.remove(mUsbDevice.getDeviceName());
                            if (usbDeviceConnectionList.containsKey(mUsbDevice)) {
                                usbDeviceConnectionList.remove(mUsbDevice);
                            }
                            ToastUtils.showBottomToast("id为：" + mUsbDevice.getDeviceName() + "，" + mUsbDevice.getManufacturerName() + "的" + "USB打印机拔出");
                        } else if (unAvailableDevice.containsKey(mUsbDevice.getDeviceName())) {
                            unAvailableDevice.remove(mUsbDevice.getDeviceName());
                            ToastUtils.showBottomToast("id为：" + mUsbDevice.getDeviceName() + "，" + mUsbDevice.getManufacturerName() + "的" + "未授权USB打印机拔出");
                        }
                    }
                } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                    if (mUsbDevice != null) {
                        if (!mUsbManager.hasPermission(mUsbDevice)) {
                            mUsbManager.requestPermission(mUsbDevice, mPermissionIntent);
                        } else {
                            handerDevice(mUsbDevice);
                        }
                    }
                }
            }
        }
    };

    private synchronized void handerDevice(UsbDevice device) {
        Log.e("USBPrinter2",new Gson().toJson(device));
        if (device == null) return;
        UsbInterface intf = device.getInterface(0);
        if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_PRINTER) {
            if (!mUsbManager.hasPermission(device)) {
                unAvailableDevice.put(device.getDeviceName(), device);
                mUsbManager.requestPermission(device, mPermissionIntent);
            } else {
                if (unAvailableDevice.containsKey(device.getDeviceName())) {
                    unAvailableDevice.remove(device.getDeviceName());
                }
                availableDevice.put(device.getDeviceName(), device);
                connectUsbPrinter(device, intf);
            }
        }
//        int count = device.getInterfaceCount();
//        for (int i = 0; i < count; i++) {
//            UsbInterface intf = device.getInterface(i);
//            if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_PRINTER) {
//                if (!mUsbManager.hasPermission(device)) {
//                    unAvailableDevice.put(device.getDeviceName(), device);
//                    mUsbManager.requestPermission(device, mPermissionIntent);
//                } else {
//                    if (unAvailableDevice.containsKey(device.getDeviceName())) {
//                        unAvailableDevice.remove(device.getDeviceName());
//                    }
//                    availableDevice.put(device.getDeviceName(), device);
//                    connectUsbPrinter(device, intf);
//                }
//            }
//        }
    }


    public void close() {
        if (mUsbDeviceConnection != null) {
            mUsbDeviceConnection.close();
            mUsbDeviceConnection = null;
        }
        if (mContext != null && mUsbDeviceReceiver != null) {
            mContext.unregisterReceiver(mUsbDeviceReceiver);
        }
        if (availableDevice != null) {
            availableDevice.clear();
        }
        if (unAvailableDevice != null) {
            unAvailableDevice.clear();
        }
        if (usbDeviceConnectionList != null) {
            usbDeviceConnectionList.clear();
        }
        mContext = null;
        mUsbManager = null;
    }

    private void connectUsbPrinter(UsbDevice mUsbDevice, UsbInterface intf) {
        Log.e("connectUsbPrinter",new Gson().toJson(mUsbDevice));
        if (mUsbDevice != null) {
            for (int i = 0; i < intf.getEndpointCount(); i++) {
                ep = intf.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        mUsbDeviceConnection = mUsbManager.openDevice(mUsbDevice);
                        printerEp = ep;
                        if (mUsbDeviceConnection != null) {
                            boolean state = mUsbDeviceConnection.claimInterface(intf, true);
                            if (state) {
                                usbDeviceConnectionList.put(mUsbDevice, mUsbDeviceConnection);
                                UsbPrintInfo info = new UsbPrintInfo();
                                info.id = mUsbDevice.getDeviceName();
                                info.isConnect = true;
                                info.name = mUsbDevice.getManufacturerName();
                                MyApplication.setUsbPrint(info);
                                if (null != listener) {
                                    listener.onAddUsbPrint(info);
                                }
                                ToastUtils.showBottomToast("id为：" + mUsbDevice.getDeviceName() + "，" + mUsbDevice.getManufacturerName() + "的" + "USB打印机已连接");
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

    private void write(byte[] bytes, UsbPrintInfo printInfo) {
        if (usbDeviceConnectionList != null && usbDeviceConnectionList.size() > 0) {
            if (printInfo != null) {
                for (UsbDevice device : usbDeviceConnectionList.keySet()) {
                    if (device.getDeviceName().equals(printInfo.id) && device.getManufacturerName().equals(printInfo.name)) {
                        int b = usbDeviceConnectionList.get(device).bulkTransfer(printerEp, bytes, bytes.length, TIME_OUT);
                    }
                }
            } else {
                for (UsbDeviceConnection connection : usbDeviceConnectionList.values()) {
                    int b = connection.bulkTransfer(printerEp, bytes, bytes.length, TIME_OUT);
                }
            }
        } else {
            Looper.prepare();
            handler.sendEmptyMessage(0);
            Looper.loop();
        }
    }

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            ToastUtils.showBottomToast("未发现可用的打印机");
        }
    };

    /**
     * 打印文字
     *
     * @param msg
     */
    public void printText(String msg, UsbPrintInfo printInfo) {
        byte[] bytes = new byte[0];
        try {
            bytes = msg.getBytes("gbk");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        write(bytes, printInfo);
    }

    /**
     * 换行打印文字
     *
     * @param msg
     */
    public void printTextNewLine(String msg, UsbPrintInfo printInfo) {
        byte[] bytes = new byte[0];
        try {
            bytes = msg.getBytes("gbk");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        write(new String("\n").getBytes(), printInfo);
        write(bytes, printInfo);
    }

    /**
     * 打印空行
     *
     * @param size
     */
    public void printLine(int size, UsbPrintInfo printInfo) {
        for (int i = 0; i < size; i++) {
            printText("\n", printInfo);
        }
    }

    /**
     * 设置字体大小
     *
     * @param size 0:正常大小 1:两倍高 2:两倍宽 3:两倍大小 4:三倍高 5:三倍宽 6:三倍大 7:四倍高 8:四倍宽 9:四倍大小 10:五倍高 11:五倍宽 12:五倍大小
     */
    public void setTextSize(int size, UsbPrintInfo printInfo) {
        write(ESCUtil.setTextSize(size), printInfo);
    }

    /**
     * 字体加粗
     *
     * @param isBold
     */
    public void bold(boolean isBold, UsbPrintInfo printInfo) {
        if (isBold) write(ESCUtil.boldOn(), printInfo);
        else write(ESCUtil.boldOff(), printInfo);
    }


    /**
     * 打印一维条形码
     *
     * @param data
     */
    public void printBarCode(String data, UsbPrintInfo printInfo) {
        write(ESCUtil.getPrintBarCode(data, 5, 90, 5, 2), printInfo);
    }


    /**
     * 打印一个二维码
     *
     * @param code
     */
    public void printQRCode(String code, UsbPrintInfo printInfo) {
        write(ESCUtil.getPrintQRCode(code, 10, 2), printInfo);
    }

    /**
     * 设置对齐方式
     *
     * @param position
     */
    public void setAlign(int position, UsbPrintInfo printInfo) {
        byte[] bytes = null;
        switch (position) {
            case 0:
                bytes = ESCUtil.alignLeft();
                break;
            case 1:
                bytes = ESCUtil.alignCenter();
                break;
            case 2:
                bytes = ESCUtil.alignRight();
                break;
        }
        write(bytes, printInfo);
    }


    /**
     * 切纸
     */
    public void cutPager(UsbPrintInfo printInfo) {
        write(ESCUtil.cutter(), printInfo);
    }

    /**
     * 绝对位置
     *
     * @param light
     * @param weight
     */
    public void setLocation(int light, int weight, UsbPrintInfo printInfo) {
        write(ESCUtil.printLocation(light, weight), printInfo);
    }


    public boolean getInitState() {
        return isInit;
    }

    public boolean isHasUSBPrinter() {
        return usbDeviceConnectionList.size() > 0;
    }


    public List<UsbDevice> getConnectDevice() {
        List<UsbDevice> devices = new ArrayList<>();
        for (UsbDevice device : availableDevice.values()) {
            if (usbDeviceConnectionList.containsKey(device)) {
                devices.add(device);
            }
        }
        return devices;
    }

    private UsbPrintListener listener;


    public void setUsbPrintListener(UsbPrintListener listener) {
        this.listener = listener;
    }

    public interface UsbPrintListener {
        void onAddUsbPrint(UsbPrintInfo usbDevice);

        void onRemoveUsbPrint(UsbPrintInfo usbDevice);
    }
}
